package com.alarm.ecp.utils;

import com.alarm.ecp.pojo.Geometry;
import com.alarm.ecp.pojo.GeometryStr;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Polygon;

import java.util.ArrayList;
import java.util.List;

public class GeoFenceUtil {
    private static final int EARTH_RADIUS_METERS = 6371000; // 地球平均半径（单位：米）

    /**
     * 判断一个经纬度点是否位于以某个中心点为圆心、指定半径的圆内
     *
     * @param centerLat   圆心纬度
     * @param centerLon   圆心经度
     * @param pointLat    待判断点的纬度
     * @param pointLon    待判断点的经度
     * @param radius      圆的半径，单位：米
     * @return            如果点在圆内或圆上返回 true，否则返回 false
     */
    public static boolean isPointInCircle(double centerLat, double centerLon,
                                          double pointLat, double pointLon, double radius) {
        double distance = haversineDistance(centerLat, centerLon, pointLat, pointLon);
        return distance <= radius;
    }

    /**
     * 使用 Haversine 公式计算两个经纬度点之间的地面距离（单位：米）
     */
    public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) {
        double lat1Rad = Math.toRadians(lat1);
        double lat2Rad = Math.toRadians(lat2);
        double deltaLat = Math.toRadians(lat2 - lat1);
        double deltaLon = Math.toRadians(lon2 - lon1);

        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
                + Math.cos(lat1Rad) * Math.cos(lat2Rad)
                * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return EARTH_RADIUS_METERS * c;
    }

    public static boolean isPointInPolygon(double pointLon, double pointLat, Coordinate[] coordinates) {
        // 创建 GeometryFactory 实例
        GeometryFactory geometryFactory = new GeometryFactory();

        // 使用坐标创建线性环(LinearRing)，这是多边形的边界
        LinearRing linearRing = geometryFactory.createLinearRing(coordinates);
        Polygon polygon = geometryFactory.createPolygon(linearRing, null); // 第二个参数为孔洞，这里没有孔

        // 测试点
        Coordinate coordinate = new Coordinate(pointLon, pointLat);

        // 判断点是否在多边形内
        return polygon.contains(geometryFactory.createPoint(coordinate));
    }

    /**
     * 判断一个经纬度点是否位于一个行政区划的边界内 TODO:先按多边形方案处理
     *
     * @param pointLon    待判断点的经度
     * @param pointLat    待判断点的纬度
     * @param polygon     行政区划的边界多边形
     * @return            如果点在多边形内或边界上返回 true，否则返回 false
     */
    public static boolean isPointInAdministrativeDivision(double pointLon, double pointLat, Polygon polygon) {
        // 创建 GeometryFactory 实例
        GeometryFactory geometryFactory = new GeometryFactory();

        // 测试点
        Coordinate coordinate = new Coordinate(pointLon, pointLat);

        // 创建点对象
        org.locationtech.jts.geom.Point point = geometryFactory.createPoint(coordinate);

        // 判断点是否在多边形内
        return polygon.contains(point);
    }

    public static void main(String[] args) {
        // 测试圆形围栏示例
        double centerLat = 39.9042;  // 北京纬度
        double centerLon = 116.4074; // 北京经度
        double testLat = 39.9052;    // 距离北京大约 100 多米的位置
        double testLon = 116.4084;
        double radius = 200;         // 半径 200 米
        boolean isInCircle = isPointInCircle(centerLat, centerLon, testLat, testLon, radius);
        System.out.println("点是否在圆内: " + (isInCircle ? "是" : "否"));

        // 测试多边形围栏示例
        // 定义多边形的坐标（按顺序），这里以一个简单的矩形为例
        Coordinate[] coordinates = new Coordinate[] {
                new Coordinate(-77.4567, 39.8282), // 经度, 纬度
                new Coordinate(-77.0000, 39.8282),
                new Coordinate(-77.0000, 40.0000),
                new Coordinate(-77.4567, 40.0000),
                new Coordinate(-77.4567, 39.8282) // 闭合点
        };
        boolean isInPolygon = isPointInPolygon(-77.2000, 39.9000, coordinates);
        System.out.println("点是否在多边形内: " + (isInPolygon ? "是" : "否"));
        isInPolygon = isPointInPolygon(-77.5000, 40.1000, coordinates);
        System.out.println("点是否在多边形内: " + (isInPolygon ? "是" : "否"));
    }

    /**
     * 获取 Geometry 中的坐标
     * @param geometry
     * @return
     */
    public static Coordinate[] getCoordinates(Geometry geometry) {
        List<List<Double[]>> coordinates = geometry.getCoordinates();
        List<Coordinate> list = new ArrayList<>();
        coordinates.forEach(coordinateList -> {
            coordinateList.forEach(coordinate -> {
                list.add(new Coordinate(coordinate[0], coordinate[1]));
            });
        });
        return list.toArray(new Coordinate[0]);
    }

    /**
     * 获取 Geometry 中的坐标
     * @param geometry
     * @return
     */
    public static Coordinate[] getCoordinatesByString(GeometryStr geometry) {
        List<String[]> coordinates = geometry.getCoordinates();
        List<Coordinate> list = new ArrayList<>();
        coordinates.forEach(coordinate -> {
            list.add(new Coordinate(Double.parseDouble(coordinate[0]), Double.parseDouble(coordinate[1])));
        });
        return list.toArray(new Coordinate[0]);
    }
}
